#ifndef __AST_H
#define __AST_H 1

#include <any>
#include <vector>
#include <string>
#include <unordered_map>
#include <stdint.h>
#include <lexer.h>
#include <common.h>
#include <type.h>
#include <operator.h>

using float64_t = double;

struct variable {
    std::string type;
    std::string name;
};


enum StatType : int {
  kNoneStat = -1,
  kEmptyStat = 0,
  kBlockStat,
  kIfStat,
  kForStat,
  kWhileStat,
  kDoWhileStat,
  kSwitchStat,
  kCaseStat,
  kStructStat,
  kEnumStat,
  kUnionStat,
  kBreakStat,
  kContinueStat,
  kLabelStat,
  kGotoStat,
  kNameStat,
  kVariableStat,
  kFuncCallArgsStat,

  kLiteralCharStat,
  kLiteralFloatStat,
  kLiteralIntegerStat,
  kLiteralStringStat,
  kUnaryOpStat,
  kBinaryOpStat,
  kTernaryOpStat,
};


class Generator;

struct BlockStat {
  std::vector<Stat> stats;
  void gen(Generator *g);
};

struct EmptyStat {};

struct TrueStat {
};
struct FalseStat {
};

struct LiteralCharStat {
  char c;
  Type type = TypeBuiltin::Char;
};
struct LiteralIntegerStat {
  int val;
  Type type = TypeBuiltin::Int;
  void gen(Generator *g);
};

struct LiteralFloatStat {
  float64_t val;
  Type type = TypeBuiltin::Float;
};

struct LiteralStringStat {
  std::string str;
};
struct NameStat {
  std::string name;
  void gen(Generator *g);
};

struct StructStat {
  std::string name;
  Type type;
  std::vector<std::string> member;
  void gen(Generator *g);
};

struct ReturnStat {
  Stat stat;
  void gen(Generator *g);
};

struct EnumStat {
  std::string name;
  std::unordered_map<std::string, int> elements;
};

struct UnionStat {
  std::string name;
  std::vector<variable> elements;
};

struct BreakStat {
  void gen(Generator *g);
};

struct ContinueStat {
  void gen(Generator *g);
};

struct TypedefStat {
  std::string raw;
  std::string alias;
};

struct LabelStat {
  std::string name;
  void gen(Generator *g);
};
struct GotoStat {
  std::string name;
  void gen(Generator *g);
};

struct CaseStat {
  LiteralIntegerStat exp;
  Stat stats;
};
struct SwitchStat {
  Stat cond;
  std::vector<Stat> cases;
  Stat def;
};
struct WhileStat {
  Stat cond;
  Stat stats;
  void gen(Generator *g);
};

struct DoWhileStat {
  Stat stats;
  Stat cond;
  void gen(Generator *g);
};

struct IfStat {
  Stat cond;
  Stat true_stat;
  Stat false_stat;
  void gen(Generator *g);
};

struct ForStat {
  Stat init, cond, step;
  Stat stat;
  void gen(Generator *g);
};

struct VarStat {
  std::string name;
  void gen(Generator *g);
};

struct VariableStat {
  Type type;
  std::string name;
  Stat init;
  bool is_static;
  void gen(Generator *g);
};

struct VariableDefineStat {
  std::vector<Stat> stat;
  void gen(Generator *g);
};

struct UnaryOpStat {
  Operator op;
  Stat exp;
  void gen(Generator *g);
};

struct BinaryOpStat {
  Operator op;
  Stat lhs, rhs;
  Type type;
  void gen(Generator *g);
};

struct TernaryOpStat {
  Stat cond;
  Stat true_stat, false_stat;
  void gen(Generator *g);
};

struct ParamStat {
  Type type;
  std::string name;
  void gen(Generator *g);
};

struct FunctionStat {
  Type ret;
  std::string name;
  std::vector<std::pair<Type, std::string>> args;
  std::vector<std::pair<Type, std::string>> local;
  Stat stats;
  void gen(Generator *g);
};

struct FuncDeclaretionStat {
  std::string rettype;
  std::string name;
  std::vector<variable> params;
};

struct FuncCallArgsStat {
  std::vector<Stat> args;
};

StatType statType(Stat stat);
void generateStat(Generator *g, Stat stat);

#endif // __AST_H
